#include "mutresmanager.h"
#include "mutmodel.h"

template CMUTSimpleManager<CMUTMD5Model>;

HRESULT CMUTTexture::CreateFromFile( LPWSTR fn ){
	LPDIRECT3DDEVICE9 pDevice = MUTState()->GetDevice();
	if ( !pDevice || 
		FAILED( D3DXCreateTextureFromFile( pDevice, fn, &pTex ) ) ){
		return E_FAIL;
	}
	name = fn;
	Ref = 0;
	return S_OK;
}

HRESULT CMUTTexture::Create( int Width, int Height, DWORD Usage, D3DFORMAT Fmt, D3DPOOL Pool ){
	LPDIRECT3DDEVICE9 pDevice = MUTState()->GetDevice();
	if ( !pDevice || 
		FAILED( D3DXCreateTexture( pDevice, Width, Height, 0, Usage, Fmt, Pool, &pTex ) ) ){
		return E_FAIL;
	}
	return S_OK;
}

void CMUTTexture::Release( HANDLE hEvent ){
	if ( manager )
		manager->ReleaseTexture( this, hEvent );
	else if ( pTex ){
		if ( hEvent )
			MUTRequestRelease( hEvent, MUTRES_TEXTURE, pTex );
		else{
			pTex->Release();
		}
		pTex = NULL;
	}
}

CMUTTexture* CMUTTexManager::GetTexture( LPWSTR fn, HANDLE hEvent ){
	auto itr = mtex.find( fn );
	if ( itr != mtex.end() ){
		itr->second->Ref++;
		return itr->second;
	}

	CMUTTexture* ptex = new CMUTTexture;
	if ( hEvent ){
		MUTRequestTextureFromFile( hEvent, fn, ptex->pTex );
		ptex->name = fn;
	}else{
		if ( FAILED( ptex->CreateFromFile( fn ) ) ){
			delete ptex;
			return NULL;
		}
	}
	ptex->Ref = 1;
	ptex->manager = this;
	mtex[ fn ] = ptex;
	return ptex;
}

void CMUTTexManager::ReleaseTexture( CMUTTexture* pTex, HANDLE hEvent ){
	pTex->Ref--;
	if ( pTex->Ref <= 0 ){
		auto itr = mtex.find( pTex->name );
		mtex.erase( itr );
		pTex->manager = NULL;
		pTex->Release( hEvent );
		delete pTex;
	}
}

void CMUTTexManager::ReleaseAll(){
	for ( auto itr = mtex.begin(); itr != mtex.end(); itr++ ){
		CMUTTexture* pTex = itr->second;
		pTex->manager = NULL;
		pTex->Release();
		delete pTex;
	}
	mtex.clear();
}


/**
 * Template Simple Manager
 *
 */
template <class T>
T* CMUTSimpleManager<T>::Get( LPWSTR fn ){
	auto itr = mres.find( fn );
	if ( itr != mres.end() ){
		return itr->second;
	}
	T* ptr = new T;
	if ( FAILED( ptr->Create( fn ) ) ){
		MUTErrorTrace( L"Simple mgr create failed" );
		return NULL;
	}
	mres[ fn ] = ptr;
	return ptr;
}

template <class T>
void CMUTSimpleManager<T>::Release(){
	for ( auto itr = mres.begin(); itr != mres.end(); itr++ ){
		itr->second->Release();
		delete itr->second;
	}
	mres.clear();
}